﻿using Common.Caching;
using Common.ExceptionHandlers;
using Common.Interfaces;
using Common.Extensions;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;

namespace Common.Behaviours;

#nullable disable

/// <summary>
/// 检查授权行为
/// </summary>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    private readonly ICurrentUserService _currentUserService;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ICacheService _cacheService;

    public AuthorizationBehaviour(
        ICurrentUserService currentUserService,
        IHttpContextAccessor httpContextAccessor,
        ICacheService cacheService)
    {
        _currentUserService = currentUserService;
        _httpContextAccessor = httpContextAccessor;
        _cacheService = cacheService;
    }

    /// <summary>
    /// 检测授权逻辑
    /// </summary>
    /// <param name="request">请求参数</param>
    /// <param name="next">进入下一管道</param>
    /// <param name="cancellationToken">取消标记</param>
    /// <returns>进入下一管道</returns>
    /// <exception cref="ForbiddenAccessException">未授权时的异常处理</exception>
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        var routeData = httpContext?.GetRouteData();
        var controllerName = routeData?.Values["controller"]?.ToString();
        var controllerType = GetControllerType(controllerName!);
        if (controllerType == null)
        {
            throw new ForbiddenAccessException("禁止访问");
        }
        if (controllerType.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any())
        {
            return await next().ConfigureAwait(false);
        }

        var actionName = routeData?.Values["action"]?.ToString();
        var actionInfo = controllerType.GetMethods()
            .FirstOrDefault(m => m.Name == actionName || m.Name == $"{actionName}Async");

        if (actionInfo == null)
        {
            throw new ForbiddenAccessException("禁止访问");
        }

        if (actionInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any())
        {
            return await next().ConfigureAwait(false);
        }

        var currentRequestToken = httpContext?.Request?.Headers["Authorization"].ToString();
        if (currentRequestToken == null)
        {
            throw new UnauthorizedException("未授权");
        }

        //var autuUserDataJson = _cacheService.Get<string>(_currentUserService.UserId!.ToAuthUserCaCheKey());
        //if (autuUserDataJson == null) 
        //{
        //    throw new UnauthorizedException("登录已过期请重新登录");
        //}
        //var autuUserData = JsonConvert.DeserializeObject<dynamic>(autuUserDataJson);
        //var lastCacheUserToken = $"Bearer {autuUserData.AccessToken}";
        //if (lastCacheUserToken != currentRequestToken) 
        //{
        //    throw new UnauthorizedException("Token已过期请重新登录");
        //}

        var httpAttributes = actionInfo.GetCustomAttributes(typeof(HttpMethodAttribute), true);
        var httpAttribute = httpAttributes.FirstOrDefault() as HttpMethodAttribute;
        if (httpAttribute != null)
        {
            var httpMethodName = httpAttribute.HttpMethods.FirstOrDefault();

            var template = string.IsNullOrEmpty(httpAttribute.Template) ? string.Empty : httpAttribute.Template;
            var accessPath = $"{httpMethodName}/api/{controllerName}/{template}";
            if (string.IsNullOrEmpty(template) && accessPath.EndsWith("/"))
            {
                accessPath = accessPath.Remove(accessPath.Length - 1);
            }

            var currentUserAllowAccessPaths = _cacheService.Get<List<string>>(_currentUserService.UserId!.ToAuthUserPathsCaCheKey());
            var allowAccess = currentUserAllowAccessPaths.Any(path => string.Equals(path, accessPath, StringComparison.OrdinalIgnoreCase));
            if (allowAccess)
            {
                return await next().ConfigureAwait(false);
            }
        }

        throw new ForbiddenAccessException("禁止访问");
    }

    /// <summary>
    /// 获取控制器类型
    /// </summary>
    /// <param name="controllerName">控制器名称</param>
    /// <returns>返回控制器类型</returns>
    private Type GetControllerType(string controllerName)
    {
        return AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .FirstOrDefault(t => typeof(ControllerBase).IsAssignableFrom(t)
            && string.Equals(t.Name, $"{controllerName}Controller", StringComparison.OrdinalIgnoreCase))!;
    }
}
